package com.xyht.medicine_management_system.modules.payment.alipay.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.msg.AlipayMsgClient;
import com.alipay.api.msg.MsgHandler;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xyht.medicine_management_system.common.commonReturn.CommonCodeEnum;
import com.xyht.medicine_management_system.common.commonReturn.CommonResult;
import com.xyht.medicine_management_system.common.commonReturn.ExceptionCast;
import com.xyht.medicine_management_system.common.util.TimeUtil;
import com.xyht.medicine_management_system.modules.coupon.constant.UserCouponRelationConstant;
import com.xyht.medicine_management_system.modules.coupon.entity.MmsUserCouponRelation;
import com.xyht.medicine_management_system.modules.coupon.entity.resp.MmsUserCouponRelationResp;
import com.xyht.medicine_management_system.modules.coupon.service.MmsUserCouponRelationService;
import com.xyht.medicine_management_system.modules.order.constant.OrderConstant;
import com.xyht.medicine_management_system.modules.order.constant.OrderMedicineInfoConstant;
import com.xyht.medicine_management_system.modules.order.constant.OrderRefundConstant;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrder;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrderMedicineInfo;
import com.xyht.medicine_management_system.modules.order.entity.MmsOrderRefund;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderMapper;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderMedicineInfoMapper;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderRefundMapper;
import com.xyht.medicine_management_system.modules.order.mapper.MmsOrderScheduleMapper;
import com.xyht.medicine_management_system.modules.order.util.OrderScheduleUtil;
import com.xyht.medicine_management_system.modules.order.util.OrderUtil;
import com.xyht.medicine_management_system.modules.payment.alipay.req.BizContentReq;
import com.xyht.medicine_management_system.modules.payment.alipay.req.RoyaltyDetail;
import com.xyht.medicine_management_system.modules.payment.wxpay.util.WxPayUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.xyht.medicine_management_system.common.util.ParamCheckUtil.isNullOrEmpty;
import static com.xyht.medicine_management_system.modules.payment.constant.CommonConstant.*;


//@Component
//@Configuration
@Log4j2
public class AlipayMsgConfig {
    private PlatformTransactionManager transactionManager; // 事务
    @Resource
    private WxPayUtil wxPayUtil;
    @Resource
    private MmsOrderMapper mmsOrderMapper;
    @Resource
    private MmsOrderScheduleMapper mmsOrderScheduleMapper;
    @Resource
    private OrderUtil orderUtil;
    @Resource
    private OrderScheduleUtil orderScheduleUtil;
    @Resource
    private MmsOrderRefundMapper mmsOrderRefundMapper;
    @Resource
    private MmsUserCouponRelationService mmsUserCouponRelationService;
    @Resource
    private MmsOrderMedicineInfoMapper mmsOrderMedicineInfoMapper;

//    @Bean
    public AlipayMsgClient alipayMsgClient() throws Exception {
        AlipayMsgClient alipayMsgClient = AlipayMsgClient.getInstance(ALIPAY_APPID);
        alipayMsgClient.setConnector("openchannel.alipay.com");
//        alipayMsgClient.setSecurityCertConfig(aliPay.getSignType(), FileUtil.readUtf8String(aliPay.getAppCertPrivateKeyPath()), aliPay.getAppCertPublicKeyPath(), aliPay.getAliPayCertPublicKeyPath(), aliPay.getAliPayRootCertPath());
        alipayMsgClient.setSecurityConfig("RSA2", ALIPAY_PRIVATE_KEY, ALIPAY_PUBLIC_KEY);
        alipayMsgClient.setCharset("utf-8");
        alipayMsgClient.setMessageHandler(new MsgHandler() {
            /**
             * 客户端接收到消息后回调此方法
             *  @param  msgApi 接收到的消息的消息api名
             *  @param  msgId 接收到的消息的消息id
             *  @param  bizContent 接收到的消息的内容，json格式
             */
            @Override
            public void onMessage(String msgApi, String msgId, String bizContent) {
                log.info("receive message. msgApi：{}，msgId：{}，bizContent：{}", msgApi, msgId, bizContent);
                // 开启事务
                DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
                // 嵌套事务 PROPAGATION_REQUIRES_NEW 每次开启一个新的事务
                dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
                // 设置嵌套事务
                TransactionStatus status = transactionManager.getTransaction(dt);

                BizContentReq bizContentReq = JSON.parseObject(bizContent, BizContentReq.class);
                if (bizContentReq == null) {
                    return;
                }
                try {
                    if (StringUtils.equals("alipay.trade.refund.depositback.completed", msgApi)) { // 退款通知
                        log.info("收单退款冲退完成通知，接收到的消息内容：{}", bizContent);
                        // 交易状态不为 SUCCESS：支付成功,则不进行操作
                        if (!bizContentReq.getDback_status().equals("S")) {
                            return;
                        }
                        // 查询退款记录是否存在
                        MmsOrderRefund orderRefund = mmsOrderRefundMapper.selectById(bizContentReq.getOut_request_no());
                        if (orderRefund == null) {
                            return;
                        }
                        // 已退款
                        if (orderRefund.getRefundAmount() != null && orderRefund.getRefundAmount().compareTo(BigDecimal.valueOf(0)) > 0) {
                            return;
                        }
                        // 查询订单是否存在
                        MmsOrder refundOrder = mmsOrderMapper.selectById(bizContentReq.getOut_trade_no());
                        // 订单不存在
                        if (refundOrder == null) {
                            return;
                        }

                        // 退还优惠券
                        if (!isNullOrEmpty(refundOrder.getCouponInfo())) { // 存在优惠券信息
                            MmsUserCouponRelationResp couponInfo = JSONObject.parseObject(refundOrder.getCouponInfo(), MmsUserCouponRelationResp.class);
                            if (couponInfo != null) {
                                MmsUserCouponRelation userCoupon = mmsUserCouponRelationService.getById(couponInfo.getId());
                                if (userCoupon != null) {
                                    // 优惠券状态修改为未使用
                                    userCoupon.setIsUse(UserCouponRelationConstant.USER_COUPON_RELATION_NOT_USE);
                                    boolean couponUpdSuccess = mmsUserCouponRelationService.updateById(userCoupon);
                                    if (!couponUpdSuccess) { // 修改失败
                                        rollback(status); // 手动回滚事务
                                        return;
                                    }
                                }
                            }
                        }

                        // 修改退款记录
                        orderRefund.setRefundId(bizContentReq.getOut_request_no()); // 微信退款id
                        orderRefund.setRefundAmount(BigDecimal.valueOf(Double.parseDouble(bizContentReq.getDback_amount()))); // 退款金额
                        orderRefund.setRefundTime(TimeUtil.StringtoDate(bizContentReq.getBank_ack_time())); // 退款时间
                        orderRefund.setStatus(OrderRefundConstant.ORDER_REFUND_STATUS_REFUNDED); // 退货状态: 已退款
                        int refundUpdNum = mmsOrderRefundMapper.updateById(orderRefund);
                        if (refundUpdNum != 1) {
                            rollback(status); // 手动回滚事务
                            return;
                        }

                        // 修改订单包含药品信息
                        MmsOrderMedicineInfo orderMedicineInfo = new MmsOrderMedicineInfo();
                        orderMedicineInfo.setRefundId(orderRefund.getId());
                        orderMedicineInfo.setType(OrderMedicineInfoConstant.ORDER_MEDICINE_INFO_REFUND);
                        int orderMedicineInfoUpdNum = mmsOrderMedicineInfoMapper.update(orderMedicineInfo, new LambdaQueryWrapper<MmsOrderMedicineInfo>()
                                .eq(MmsOrderMedicineInfo::getOrderId, refundOrder.getId()));
                        if (orderMedicineInfoUpdNum < 1) {
                            ExceptionCast.cast(CommonResult.failed(CommonCodeEnum.FAIL));
                        }

                        // 修改订单状态
                        Date nowDate = new Date(); // 当前时间
                        refundOrder.setIsClose(OrderConstant.ORDER_IS_CLOSE_YES); // 订单结束
                        refundOrder.setEndTime(nowDate); // 订单结束时间
                        int refundOrderUpdNum = mmsOrderMapper.updateById(refundOrder);
                        if (refundOrderUpdNum != 1) { // 修改失败
                            rollback(status); // 手动回滚事务
                            return;
                        }
                    } else if (StringUtils.equals("alipay.trade.order.settle.notify", msgApi)) { // 分账通知
                        log.info("交易分账结果通知，接收到的消息内容：{}", bizContent);
                        RoyaltyDetail royaltyDetail = bizContentReq.getRoyalty_detail_list().get(0);
                        // 查询订单
                        MmsOrder profitOrder = mmsOrderMapper.selectById(bizContentReq.getOut_request_no());
                        if (profitOrder == null) {
                            rollback(status); // 手动回滚事务
                            return;
                        }
                        if (royaltyDetail.getState().equals("FAIL")) {
                            // 订单异常
                            profitOrder.setIsAbnormal(true);
                            int profitOrderUpdNum = mmsOrderMapper.updateById(profitOrder);
                            if (profitOrderUpdNum != 1) {
                                rollback(status); // 手动回滚事务
                                return;
                            }
                        }
                        if (!royaltyDetail.getState().equals("SUCCESS")) {
                            rollback(status); // 手动回滚事务
                            return;
                        }

                        // 已分账
                        if (!isNullOrEmpty(profitOrder.getProfitSharingTime())) {
                            rollback(status); // 手动回滚事务
                            return;
                        }

                        profitOrder.setProfitSharingTime(TimeUtil.StringtoDate(royaltyDetail.getExecute_dt()));
                        int profitOrderUpdNum = mmsOrderMapper.updateById(profitOrder);
                        if (profitOrderUpdNum != 1) {
                            rollback(status); // 手动回滚事务
                            return;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    // 手动回滚事务
                    transactionManager.rollback(status);
                } finally {
                    if (status.isNewTransaction() && !status.isCompleted()) {
                        transactionManager.commit(status);
                    }
                }
            }
        });
        alipayMsgClient.connect();
        log.info("建立支付宝websocket连接");
        return alipayMsgClient;
    }

    /**
     * 手动回滚事务
     *
     * @param status 嵌套事务
     */
    private void rollback(TransactionStatus status) {
        // 手动回滚事务
        transactionManager.rollback(status);
        if (status.isNewTransaction() && !status.isCompleted()) {
            transactionManager.commit(status);
        }
    }

}
